import re
import sys
import time
from queue import Queue, Empty
from threading import Thread, Lock

from src.utils.method import Method
from src.base.datatype import ProcessLog, RobotLog
from src.conf.conf_manager import ConfManager
from src.network.client import Client


class Logger:
    def __init__(self, conf: ConfManager):
        """日志管理器"""
        self.__conf = conf
        # 内部参数
        self.__log_queue = Queue()
        self.__robot_log = Queue()
        self.__cmd_queue = Queue()
        self.__report_log = Queue()
        self.__header_regs: list = ["(?<=\\[Server]).*", "(?<=\\[INFO]).*", "(?<=\\[glist]).*",
                                    "(?<=\\[INFO ]).*", "(?<=\\[Server thread/INFO]).*"]
        self.__record_lock = Lock()
        self.record_log_num = 0
        self.__record_log = []
        self.file_hold = False

    def __do_reg_print(self) -> None:
        """正则匹配处理"""
        while True:
            log: ProcessLog = self.__log_queue.get()
            # 输出记录与屏蔽
            if self.__if_shield_log(log):
                continue
            self.__add_record_log(log)
            try:
                print(log.color_text)
            except Exception as e:
                print(e)
            # 复杂打印缓冲供再次捕获
            sys.stdout.flush()
            # 热备份的匹配
            if re.search("Data saved. Files are now ready to be copied.", log.text) \
                    or re.search("数据已保存。文件现已可供复制。", log.text):
                self.__log_queue.get()
                self.file_hold = True
            # 用户设定的匹配
            for reg in self.__conf.robot_regex.content:
                try:
                    # 匹配成功才进行后续操作
                    res = re.findall(reg["正则"], log.text)
                    if not res:
                        continue
                    # 符合过滤列表则过滤内容
                    need_filter = False
                    for filter_reg in reg.get("过滤列表", []):
                        if re.search(filter_reg, log.text):
                            need_filter = True
                            break
                    if need_filter:
                        continue
                    # 文本追加处理
                    addon_num: int = reg.get("输出追加行数", 0)
                    execute_cmd = reg.get("执行命令", [])
                    if type(execute_cmd) is str:
                        execute_cmd = [execute_cmd]
                    # 广播任务处理
                    report_addr: str = reg.get("广播地址")
                    report_format: str = reg.get("广播格式", "")
                    if report_addr:
                        self.__report_log.put((report_addr, log.text, report_format))
                    # 返回消息与执行命令处理
                    addon_lines = self.__addon_lines(addon_num)
                    cmd_list = []
                    for cmd in execute_cmd:
                        cmd = Method.deal_placeholder(cmd, res, log.text)
                        if addon_lines != "":
                            cmd += "\n" + addon_lines
                        cmd_list.append(cmd)
                    self.__cmd_queue.put(cmd_list)
                except Exception as err:
                    print(f"[DLS][WARN][REG] 错误的匹配: {reg} 原因: {err}")

    def __do_report_task(self) -> None:
        """处理播报任务"""
        while True:
            task: tuple = self.__report_log.get()
            time.sleep(0.2)
            Client.send_raw(task[0], task[1], task[2])

    def __addon_lines(self, num: int) -> str:
        """根据数量追加输出"""
        lines = []
        for _ in range(num):
            # 追加输出最多等待3秒
            try:
                log_x: ProcessLog = self.__log_queue.get(timeout=3)
            except Empty:
                continue
            while self.__if_shield_log(log_x):
                log_x: ProcessLog = self.__log_queue.get()
            # 输出记录与屏蔽
            self.__add_record_log(log_x)
            try:
                print(log_x.color_text)
            except Exception as e:
                print(e)
            sys.stdout.flush()
            # 剔除前缀
            pla: str = log_x.text
            for header_reg in self.__header_regs:
                pla = Method.del_info_header(header_reg, pla)
            # 不为空字符串时才追加输出
            if pla:
                lines.append(pla)
        return "\n".join(lines)

    def __if_shield_log(self, log: ProcessLog) -> bool:
        """判断是否需要屏蔽"""
        for shield_reg in self.__conf.conf.output_shield:
            if re.search(shield_reg, log.text):
                return True
        return False

    def add_log(self, raw_text: str) -> None:
        """添加消息至日志队列"""
        self.__log_queue.put(ProcessLog(raw_text))

    def add_robot_msg(self, text: str) -> None:
        """添加消息至机器人日志队列"""
        # 累计过多日志时清除内容
        if self.__robot_log.qsize() > 200:
            self.__robot_log.get()
        if self.__conf.robot_conf.on and text:
            self.__robot_log.put(RobotLog(text))

    def get_robot_log(self) -> RobotLog:
        """获取合并机器人日志"""
        size = self.__robot_log.qsize()
        # 最大合并10条日志
        if size > 10:
            size = 10
        combine_log = RobotLog()
        for _ in range(size):
            log: RobotLog = self.__robot_log.get()
            combine_log += log
        return combine_log

    def add_cmd(self, cmd: str | list):
        """添加一条命令"""
        if type(cmd) is str:
            cmd = [cmd]
        self.__cmd_queue.put(cmd)

    def get_cmd_lists(self) -> list:
        """取出cmd队列返回内容列表"""
        cmd_lists = []
        size = self.__cmd_queue.qsize()
        for _ in range(size):
            cmd_list: str = self.__cmd_queue.get()
            cmd_lists.append(cmd_list)
        return cmd_lists

    # 添加输出日志
    def __add_record_log(self, log: ProcessLog):
        with self.__record_lock:
            if log.text == "":
                return
            self.record_log_num += 1
            if self.record_log_num > 1000000:
                self.record_log_num = 0
            if len(self.__record_log) >= 200:
                self.__record_log.pop(0)
            self.__record_log.append({"log_id": self.record_log_num,
                                      "text": log.text, "color_text": log.color_text})

    # 获取最新输出日志
    def latest_record_log(self, log_id=0):
        with self.__record_lock:
            latest_log = []
            # 反向索引进行查找
            reversed_index = list(range(len(self.__record_log)))
            reversed_index.reverse()
            for i in reversed_index:
                log = self.__record_log[i]
                if log["log_id"] == log_id:
                    break
                latest_log.append(log)
        # 结果还原为正向
        latest_log.reverse()
        return latest_log

    def start(self) -> None:
        """启动日志管理器"""
        thx = Thread(target=self.__do_reg_print, daemon=True)
        thx.start()
        thy = Thread(target=self.__do_report_task, daemon=True)
        thy.start()
